#pragma once

#ifndef _MY_STRATEGY_H_
#define _MY_STRATEGY_H_

#include "Strategy.h"
#include "MyStructures.h"
#include "CellChecker.h"

#include <fstream>
#include <sstream>
#include <set>
#include <math.h>

using namespace model;
using namespace std;

static vector<Target> targets;
static vector<BlockSignal> signals;

class MyStrategy : public Strategy
{
private:
	//ofstream log;
	bool logOpen;

	SeenCells seenCells;

	OneMoveDirective directive;
	
	const Trooper *pself;
	const World *pworld;
	const Game *pgame;
	const vector<vector<CellType> > *pcells;
	vector<Trooper> team, enemies;

	bool IsBetter (const Point& a, const Point& b, const Point& target = Point (-1, -1));
	void SortCells (vector<Point>& cells, const Point& target = Point (-1, -1));
	void TryEnqueue (const Point& p, vector<BFSStep>& queue, set<Point>& known, int to_handle, const Point& target, bool stepover, int& obstacleQueueIndex);
	void BFSNext (vector<BFSStep>& queue, set<Point>& known, int to_handle, const Point& target, int& targetIdx, bool stepover, int& obstacleQueueIndex, const vector<Bonus>& bonuses);
	void BFSUntil (vector<BFSStep>& queue, set<Point>& known, int to_handle, int& targetIdx, bool stepover, int& obstacleQueueIndex, const vector<Bonus>& bonuses, CellChecker& checker, Condition condition);
	vector<Point> GetPathToTarget (const Point& current, const Point& goal);
	bool IsCellVisibleToMyTeam (const Point& cellLocation, TrooperStance cellStance);
	vector<Trooper> GetTeam ();
	bool IsTeamTogether ();
	bool AmIUnderTheGun ();
	int GetCellDistance (const Point& to, const Point& from, bool transparentTroopers, vector<Point>& pathToGoal);
	bool GrabBonusAndComeBack (Move& move);

	void UpdateTargets ();
	void UpdateJoincalls ();
	void UpdateHelpcalls (vector<Trooper>& actualHelpcallers);
	void UpdateBonuses ();
	void UpdateEnemies ();
	void UpdateSeenCells ();
	void UpdateSeenCells (const Trooper* whoMoves, const Trooper& teammate);

	bool IsHolding (BonusType bonus);
	BonusType TargetSubtypeToBonusType (TargetSubtype subtype);
	TrooperType TargetSubtypeToEnemyType (TargetSubtype subtype);
	bool LocateTeammate (TrooperType type, Point& location);
	int GetPriority (Target& target);
	size_t TopTargetIndex ();

	void GetUpAndStepCloser (Target& target, Move& move);
	void ApproachTarget (Target& target, Move& move);
	void ApproachEnemy2 (Target& target, Move& move);
	bool ThrowGrenade (vector<Trooper>& enemies, Move& move);
	TrooperStance GetLowestShootingStance (const Trooper& enemy);
	int GetPointsToShoot (TrooperStance stance, int damageLimit);

	void CommitToStepping (Move& move, Direction direction);
	void CommitToStepping (Move& move, int x, int y);
	void CommitToShooting (Move& move, int x, int y);

	bool EatFieldRation (Move& move);
	bool CureSelf (Move& move);

	int GetShotDamage ();
	int GetShotDamage (TrooperStance stance);
	int GetMoveCost (TrooperStance stance);

	void LogSituation (size_t topTargetIdx);

	bool ReceiveSignals	 (BlockSignal& signalToMe);
	bool IsStepPossible (int x, int y, int& rank, vector<TrooperType>& blockers);
	bool LetOutStep (Point& step, TrooperType& blocker);
	bool LetOut (Move& move);
	bool AmILeader (int& joincallIdx);

	void BookBonus (size_t targetIdx);

	bool GetHideDirective (OneMoveDirective& directive, int& cost, int runFromX, int runFromY);
	bool ExecuteDirective (Move& move);
	Point GetEndPoint (const OneMoveDirective d);
	//int PointsToHide (vector<Point>& _hidePath, vector<Point>& extraWatchOuts, const Point& start, int havePointsToHide);
	//bool StepToHide (Move& move);
	bool IsSafeStep (const Point& p, OneMoveDirective& lookupDirective);
	vector<Point> GetWatchoutCells (const Point& p);

	bool ResetCellTarget (Target& target, Move& move);

	int CalcCellDangerRate (const Point& cell, vector<Point>& dangerCells);
	OneMoveDirective GetSafeMoveDirective (vector<Point>& pathToTarget, bool usefulComebackDirective);
	int ChooseSafestPointOfPath (const vector<Point>& path, int& minDangerRate);
	void AddStepToSaferCell (OneMoveDirective& currentDirective, int pointsLimit);

	///ENEMY APPROACH
	bool GET_ENEMY_BY_TARGET (const Target& target, Trooper& enemy);
	bool CAN_KILL (const Trooper& enemy, OneMoveDirective& moveDirective, const int pointLimit);
	bool CAN_MEDIKIT_MOST_INJURED_NOW (OneMoveDirective& moveDirective);
	bool CAN_DO_DAMAGE_AND_HIDE (OneMoveDirective& moveDirective, const Trooper& enemy, const int pointsLimit, const Point& hideStart);
	bool GetDamageDirective (OneMoveDirective& damageDirective, const Trooper& enemy, const int maxAttackMoints, const int attackPoints, bool& rationUsed);
	int GetActionCost (ActionType action, TrooperStance stance);
	bool CAN_HIDE (OneMoveDirective& moveDirective);
	int ATTACK_MAX (OneMoveDirective& attackDirective, const Trooper& enemy);
	void LOWER_MAX (OneMoveDirective& moveDirective);
	void RAISE_MAX (OneMoveDirective& moveDirective);
	bool HIS_TEAM_STANDING_WOULD_SEE_ME (const Trooper& enemy);
	void LOWER_TO_SHOOT (OneMoveDirective& lowerDirective, const Trooper& enemy);
	bool NEED_TO_HIDE ();
	bool CAN_GET_TO_SHOOT_AND_KILL (OneMoveDirective& moveDirective, const Trooper& enemy);
	bool GetGetToShootDirective (OneMoveDirective& getToShootDirective, int& getToShootCost, Point& shootPoint, const Trooper& enemy);
	bool CAN_GET_TO_SHOOT_AND_DODAMAGE_AND_HIDE (OneMoveDirective& moveDirective, const Trooper& enemy);
	void HIDE_CLOSER (OneMoveDirective& moveDirective, const Trooper& enemy);
	Trooper ConstructEnemyFromTarget (const Target& target);
	OneMoveDirective DO_COMEBACK_ACT ();
	OneMoveDirective MEDIKIT_SMB ();
	OneMoveDirective HEAL_SMB ();
	OneMoveDirective SNITCH_BONUS ();
	bool CAN_GRENADE_THROW (OneMoveDirective& moveDirective, const Trooper& enemy);
	bool ThrowGrenade2 (vector<Trooper>& enemies, Move& move);

public:
	MyStrategy () : directive (OneMoveDirective (0)), logOpen (false), seenCells () {maxVisionRange = -1; maxShootingRange = -1;}
    void move (const Trooper& self, const World& world, const Game& game, Move& move);
};

#endif
